/**
 * Copyright (c) 2017-2024 Nop Platform. All rights reserved.
 * Author: canonical_entropy@163.com
 * Blog:   https://www.zhihu.com/people/canonical-entropy
 * Gitee:  https://gitee.com/canonical-entropy/nop-entropy
 * Github: https://github.com/entropy-cloud/nop-entropy
 */
package com.gitee.wsl.text.marker


/**
 * 对文本区间增加附加标记
 */
abstract class Marker(/**
                        * 标记区间的起始位置，从0开始
                        */
                       val textBegin: Int,

                      /**
                        * 标记区间的结束位置。实际区间不包含此位置
                        */
                       val textEnd: Int) :  Comparable<Marker> {

    init {

        require(textBegin <= textEnd){"marker start should be less than end"}
        require(textBegin >= 0) { "marker start should be positive" }
    }

    fun within(begin: Int, end: Int): Boolean {
        return this.textBegin >= begin && this.textEnd <= end
    }

    /**
     * 返回标记部分的文本
     *
     * @param text 文本整体
     * @return marker所标记部分的文本
     */
    fun getMarkedText(text: CharSequence): String {
        return text.subSequence(textBegin, textEnd).toString()
    }

    override fun toString(): String {
        val sb = StringBuilder()
        return appendPos(sb).toString()
    }

    protected fun appendPos(sb: StringBuilder): StringBuilder {
        sb.append(textBegin)
        if (textEnd != textBegin + 1) sb.append('-').append(textEnd)
        return sb
    }

    override fun compareTo(other: Marker): Int {
        return textBegin.compareTo(other.textBegin)
    }

    fun countOccur(text: String, c: Char): Int {
        var count = 0
        for (i in textBegin until textEnd) {
            if (text[i] == c) count++
        }
        return count
    }

    val isEmpty: Boolean
        get() = textBegin == textEnd

    /**
     * marker所标记的区间的长度
     *
     * @return 区间长度
     */
    fun length(): Int {
        return textEnd - textBegin
    }

    fun intersect(o: Marker): Boolean {
        if (o.textBegin in textBegin..<textEnd) return true
        if (o.textBegin <= textBegin && o.textEnd > textBegin) return true
        return false
    }

    /**
     * marker的名称，一般用于显示
     */
    open val name: String?
        get() = null

    /**
     * 移动整个标记区间的位置。例如标记区间[1,5)移动offset=1之后得到新的区间[2,6)
     *
     * @param offset 移动的步长。
     * @return 新生成的标记对象
     */
    abstract fun offset(offset: Int): Marker

    companion object
}
